package me.barcodescanner.util;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import net.sourceforge.zbar.Config;
import net.sourceforge.zbar.Image;
import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;

import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import me.barcodescanner.App;
import me.barcodescanner.zbar.ScannerActivity;
import me.barcodescanner.zbar.ZBarcodeFormat;
import me.barcodescanner.zbar.BitmapAndType;
import me.barcodescanner.zbar.Result;
import me.zxingcore.qrcode.QRCodeEncoder;

/**
 * Created by luxianyue on 2018/3/21.
 */

public class ZBarHelper {

    public static final int CODE_TYPE_ONE_D = 1;
    public static final int CODE_TYPE_QR_CODE = 2;
    public static final int RESULT_DATA = 1;
    public static final int RESULT_EMPTY = 0;

    private static OnScanListener mOnScanListener;
    private static OnParseListener mListener;
    private static ExecutorService mFixThreadPool;
    private static ParseTask mParseTask;

/*    *//**
     * 扫描一维码（条形码）
     *//*
    public static void startScanOneDCode(String promptText) {
        startScanCode(CODE_TYPE_ONE_D, promptText);
    }

    public static void startScanOneDCode(Activity ay) {

    }

    *//**
     * 扫描二维码
     *//*
    public static void startScanQRCode(String promptText) {
        startScanCode(CODE_TYPE_QR_CODE, promptText);
    }

    *//**
     * 扫码
     *//*
    public static void startScanAllCode(String promptText) {
        startScanCode(0, promptText);
    }*/

   /* private static void startScanCode(int codeType, String promptText) {
        Intent intent = new Intent(App.getContext(), ScannerActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("type", codeType);
        intent.putExtra("prompText", promptText);
        App.getContext().startActivity(intent);
    }*/

    /**
     * 编码
     */
    public static QRCodeEncoder.Builder newQREncodeBuilder() {
        return new QRCodeEncoder.Builder();
    }

    /**
     * 解析图片一维码 （条形码）
     * @param imgPath
     * @return
     */
    public static void parseBarCode(String imgPath, boolean isCompress) {
        parseBarCode(getBitmap(imgPath, isCompress));
    }

    public static void parseBarCode(Bitmap bitmap) {
        decodeCode(bitmap, CODE_TYPE_ONE_D);
    }

    /**
     * 解析图片二维码
     * @param imgPath
     * @return
     */
    public static void parseQRCode(String imgPath, boolean isCompress) {
        parseQRCode(getBitmap(imgPath, isCompress));
    }

    public static void parseQRCode(Bitmap bitmap) {
        decodeCode(bitmap, CODE_TYPE_QR_CODE);
    }

    /**
     * 解析图片码
     * @param imgPath
     * @return
     */
    public static void parseMultiCode(String imgPath, boolean isCompress) {
        parseMultiCode(getBitmap(imgPath, isCompress));
    }

    public static void parseMultiCode(Bitmap bitmap) {
        decodeCode(bitmap, 0);
    }

    private synchronized static Bitmap getBitmap(String imagePath, boolean isCompress) {
        Bitmap bitmap = null;
        if (isCompress) {
            BitmapFactory.Options options = ImageDecode.getJustBoundsOption(imagePath);
            int width = options.outWidth;
            int height = options.outHeight;
            options = ImageDecode.getBitmapOptions(App.getContext());
            options.inSampleSize = ImageDecode.computeSampleSize(width, height, 600, 600);

            bitmap = BitmapFactory.decodeFile(imagePath, options);
        } else {
            bitmap = BitmapFactory.decodeFile(imagePath);
        }
        return bitmap;
    }

    /**
     * 解析图片
     *
     * @param bitmap
     * @return
     */
    private static void decodeCode(Bitmap bitmap, int codeType) {
        if (bitmap != null) {
            if (mParseTask == null) {
                mParseTask = new ParseTask();
            }
            if (mFixThreadPool == null) {
                mFixThreadPool = Executors.newFixedThreadPool(1);
            }

            mParseTask.setBitmapAndCodeType(bitmap, codeType);
            mFixThreadPool.execute(mParseTask);
        }
    }

    static class ParseTask implements Runnable {
        Queue<BitmapAndType> mParseQueue;

        ParseTask() {
            mParseQueue = new LinkedList<>();
        }

        public void setBitmapAndCodeType(Bitmap bitmap, int codeType) {
            mParseQueue.offer(new BitmapAndType(codeType, bitmap));
        }

        @Override
        public void run() {
            doParse();
        }

        private void doParse() {
            TaskHandler handler = new TaskHandler();

            if (!mParseQueue.isEmpty()) {
                BitmapAndType bt = mParseQueue.poll();
                Image image = new Image(bt.bitmap.getWidth(), bt.bitmap.getHeight(), "Y800");
                image.setData(Bitmap2YUV.getYUV420sp(bt.bitmap.getWidth(), bt.bitmap.getHeight(), bt.bitmap));
                ImageScanner scanner = new ImageScanner();

                out : {
                    if (bt.codeType == CODE_TYPE_ONE_D) {
                        scanner.setConfig(0, Config.ENABLE, 0);
                        for (ZBarcodeFormat format : ZBarcodeFormat.ONE_D_CODE_FORMATS) {
                            scanner.setConfig(format.getId(), Config.ENABLE, 1);
                        }
                        break out;
                    }
                    if (bt.codeType == CODE_TYPE_QR_CODE) {
                        scanner.setConfig(0, Config.ENABLE, 0);
                        scanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1);
                        break out;
                    }

                    scanner.setConfig(0, Config.ENABLE, 1);
                }

                int var = scanner.scanImage(image);
                if (var != 0) {
                    SymbolSet symbolSet = scanner.getResults();
                    Result rawResult = null;
                    for (Symbol sym : symbolSet) {
                        String symData = null;
                        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                            symData = new String(sym.getDataBytes(), StandardCharsets.UTF_8);
                        } else {
                            symData = sym.getData();
                        }

                        rawResult = new Result();
                        rawResult.setContents(symData);
                        rawResult.setBarcodeFormat(ZBarcodeFormat.getFormatById(sym.getType()));
                        handler.obtainMessage(RESULT_DATA, rawResult).sendToTarget();
                    }

                } else {
                    handler.sendEmptyMessage(RESULT_EMPTY);
                }


                bt.bitmap.recycle();
                bt.bitmap = null;
            } else {
                handler.sendEmptyMessage(RESULT_EMPTY);
            }
        }
    }

    static class TaskHandler extends Handler{
        public TaskHandler() {
            super(Looper.getMainLooper());
        }
        @Override
        public void handleMessage(Message msg) {
            if (mListener != null) {
                switch (msg.what) {
                    case RESULT_EMPTY:
                        mListener.onResult(null);
                        break;
                    case RESULT_DATA:
                        mListener.onResult((Result) msg.obj);
                        break;
                }
            }
        }
    }

    static class ImageDecode{
        private static final int DEFAULT_DENSITY = 240;
        private static final float SCALE_FACTOR = 0.75f;
        private static final Bitmap.Config DEFAULT_BITMAP_CONFIG = Bitmap.Config.RGB_565;

        private static BitmapFactory.Options getJustBoundsOption(String imagePath) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(imagePath, options);
            return options;
        }

        private static int computeSampleSize(int width, int height, int maxWidth, int maxHeight) {
            int inSampleSize = 1;
            if (height > maxHeight || width > maxWidth) {
                int heightRate = Math.round((float) height / (float) maxHeight);
                int widthRate = Math.round((float) width / (float) maxWidth);
                inSampleSize = heightRate < widthRate ? heightRate : widthRate;
            }
            if (inSampleSize % 2 != 0) {
                inSampleSize -= 1;
            }
            return inSampleSize <= 1 ? 1 : inSampleSize;
        }

        private static BitmapFactory.Options getBitmapOptions(Context context) {

            BitmapFactory.Options options = new BitmapFactory.Options();
            //options.inPreferredConfig = DEFAULT_BITMAP_CONFIG;
            options.inPurgeable = true;
            options.inInputShareable = true;

            int displayDensityDpi = context.getResources().getDisplayMetrics().densityDpi;
            float displayDensity = context.getResources().getDisplayMetrics().density;
            if (displayDensityDpi > DEFAULT_DENSITY && displayDensity > 1.5f) {
                int density = (int) (displayDensityDpi * SCALE_FACTOR);
                options.inDensity = density;
                options.inTargetDensity = density;
            }
            return options;
        }
    }

    public static OnScanListener getOnScanListener() {
        return mOnScanListener;
    }

    public static void setOnScanListener(OnScanListener OnScanListener) {
        ZBarHelper.mOnScanListener = OnScanListener;
    }

    public static void setParseListener(OnParseListener listener) {
        ZBarHelper.mListener = listener;
    }

    public interface OnParseListener {
        void onResult(Result result);
    }

    public interface OnScanListener {
        void onResult(Result result);
    }

}
